package com.jltx.xq.coroutinesandrxpro.coroutines

import android.os.Handler
import android.util.Log
import com.jltx.xq.coroutinesandrxpro.rxjava.RxJava2Learn1
import com.jltx.xq.coroutinesandrxpro.rxjava.RxJava2Learn1.TAG
import com.jltx.xq.coroutinesandrxpro.rxjava.RxJava2Learn1.heavyInitialization
import com.jltx.xq.coroutinesandrxpro.rxjava.RxJava2Learn2
import kotlinx.coroutines.*

/**
 * @author aidenquan
 *         Created by junlintianxia on 2021/07/26.
 */
object CoroutinesLearn2 {

    fun intervalCancel(handle: Handler) {
        val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
            Log.d(TAG, "Cor ${coroutineContext[CoroutineName]} $throwable")
        }
        val job = GlobalScope.launch(Dispatchers.IO + exceptionHandler) {
            delay(1000L)
            Log.d(TAG, "Cor interval 1 ${Thread.currentThread()}")
            delay(1000L)
            throw Exception("intervalCancel 异常")
            Log.d(TAG, "Cor interval 2 ${Thread.currentThread()}")
            delay(1000L)
            Log.d(TAG, "Cor interval 3 ${Thread.currentThread()}")
        }
        handle.postDelayed({
            job.cancel()
            Log.d(TAG, "Cor intervalCancel cancel${Thread.currentThread()}")
        }, 2500L)
    }

    /**
     * 类似于 RxJava 的 CompositeDisposable，调用一次就可以销毁多个订阅者
     * 当共享 Job 给不同的协程时，一定要注意：当你取消一个 Job 后，你必须重新创建它，你不可以再将已取消的 Job 分配给另一个协程。
     */
    fun multipleJobCancel(handle: Handler) {
        val parentJob = Job()

        val deferred1 = GlobalScope.async(parentJob + Dispatchers.IO) {
            Log.d(TAG, "Cor multipleJobCancel1 ${Thread.currentThread()}")
        }

        val deferred2 = GlobalScope.async(parentJob + Dispatchers.IO) {
            delay(2000L)
            Log.d(TAG, "Cor multipleJobCancel2 ${Thread.currentThread()}")
        }

        handle.postDelayed({
            parentJob.cancel()
            Log.d(TAG, "Cor multipleJobCancel2 cancel${Thread.currentThread()}")
        }, 1000L)
    }


    /**
     * 协程取消场景，如同在 RxJava 中检查订阅者是否存在一样，我们需要检查协程是否活跃。
     */
    fun customIntervalWithCancel(handle: Handler) {
        val job = GlobalScope.launch(Dispatchers.Main) {
            try {
                withContext(Dispatchers.IO) {
                    for (i in 1..5) {
                        if (!isActive) {
                            break
                        }
                        delay(1000L)
                        heavyInitialization()
                    }
                }
                Log.d(TAG, "Cor customIntervalWithCancel success ${Thread.currentThread()}")
            } catch (e: Exception) {
                Log.d(TAG, "Cor customIntervalWithCancel fail $e ${Thread.currentThread()}")
            }
        }
        handle.postDelayed({
            job.cancel()
            Log.d(TAG, "Cor customIntervalWithCancel cancel${Thread.currentThread()}")
        }, 1500L)
    }

    /**
     * 协程里面不能直接使用Thread.sleep()
     * 如果你使用 Thread.sleep 而不是延迟，因为它阻塞了线程而不是挂起协程，它不会取消它
     * Thread.sleep 不会为我们取消执行。它甚至不是一个暂停功能！即使我们调用了 job.cancel()，该协程也不会被取消。
     *
     */
    fun customIntervalWithCancel2(handle: Handler) {
        val job = GlobalScope.launch(Dispatchers.Main) {
            try {
                withContext(Dispatchers.IO) {
                    Log.d(TAG, "doSomething1")
                    Thread.sleep(1000L)
                    Log.d(TAG, "doSomething2")
                }
                Log.d(TAG, "Cor customIntervalWithCancel2 success ${Thread.currentThread()}")
            } catch (e: Exception) {
                Log.d(TAG, "Cor customIntervalWithCancel2 fail $e ${Thread.currentThread()}")
            }
        }
        handle.postDelayed({
            job.cancel()
            Log.d(TAG, "Cor customIntervalWithCancel2 cancel${Thread.currentThread()}")
        }, 900L)
    }

    /**
     * 在这种情况下，您不应该使用 Thread.sleep 。如果您真的需要，取消该协程的一种方法是检查它在线程阻塞之前和之后是否处于活动状态。
     */
    fun customIntervalWithCancel3(handle: Handler) {
        val job = GlobalScope.launch(Dispatchers.Main) {
            try {
                withContext(Dispatchers.IO) {
                    Log.d(TAG, "doSomething1")
                    if (!isActive) return@withContext
                    Thread.sleep(1000L)
                    if (!isActive) return@withContext
                    Log.d(TAG, "doSomething2")
                }
                Log.d(TAG, "Cor customIntervalWithCancel2 success ${Thread.currentThread()}")
            } catch (e: Exception) {
                Log.d(TAG, "Cor customIntervalWithCancel2 fail $e ${Thread.currentThread()}")
            }
        }
        handle.postDelayed({
            job.cancel()
            Log.d(TAG, "Cor customIntervalWithCancel2 cancel${Thread.currentThread()}")
        }, 900L)
    }
}
